# Creating a new Attachment

There are two different ways to upload file attachments.  Direct CDN upload, or Kantata OX server upload.
## Direct CDN Upload
Uploading directly to the CDN is a three step process but allows for faster uploading, significantly
larger attachments, and more accurate upload progress information.
Retrieving upload credentials has two required fields, `direct` and `attachment`.  The `direct` field must
be set to `true`.  The `attachment` field must include two attributes:
- `type` (required) must be `post_attachment` or `receipt`.
- `filename` (required) is the filename of the file to be uploaded.

The file name must not contain spaces or special characters other than an underscore ("_") or a hyphen ("-"),
otherwise the file upload will fail.
After successfully creating an attachment, an upload url and credentials will be returned in JSON format
with an HTTP 200 status code.

```
curl --form "direct=true" --form "attachment[filename]=attachment.doc"
--form "attachment[type]=post_attachment" "https://api.mavenlink.com/api/v1/attachments.json"
```
The response JSON will then contain the information to upload the file:

```
{
   "id": 2,
   "action": "[upload url]",
   "fields":{
      "utf8": "✓",
      "key": " ... ",
      "Content-Disposition": "attachment; filename="attachment.doc"; filename*=UTF-8''attachment.doc",
      "success_action_status": 201,
      "AWSAccessKeyId": " ... ",
      "acl": "private",
      "policy": " ... ",
      "signature": " ... "
   }
}
```
A second POST request can then be made to the provided `action` with the field values
returned in the JSON response, in addition to the file data. The AWSAccessKeyId field value
is only active for 5 seconds, so these consecutive calls are meant to be made in quick succession via a script.
Other than `$file`, variables in the request that start with $ are the values represented by the " ... " blanks in the JSON response.

```
curl -X POST "[upload url]" -H 'cache-control: no-cache' --form 'AWSAccessKeyId='$awsKey --form 'Content-Disposition="attachment; filename="$file"; filename*=UTF-8''''''$file"' --form 'x-amz-server-side-encryption=AES256' --form 'key='$key --form 'policy='$policy --form 'signature='$sig --form 'acl=private' --form 'success_action_status=201' --form 'utf8=✓' --form 'file=@'$file
```
Finally, once the upload has completed successfully, a 'sync' request (specified below) is necessary to
mark the upload as complete.
Below is a simplified example using ruby to achieve the same thing as with the `curl` commands above:

```ruby
#!/usr/bin/env ruby

require 'net/https'
require "uri"
require 'json'

TOKEN="Bearer <your-secret-here>"
ATTACHMENTS_ENDPOINT="https://api.mavenlink.com/api/v1/attachments.json"
BOUNDARY = "AaB03x" # Make sure it is not present in the file you're uploading.

file = ARGV[0]
filename = File.basename(file)

uri = URI.parse(ATTACHMENTS_ENDPOINT)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request['Authorization'] = TOKEN
request.set_form_data(first_request_params)
response = http.request(request)
first_response = JSON.parse(response.body)

# for the second request we manually build the request body
post_body = []

second_request_params = first_response["fields"].merge({ "file" => File.open(file) })
second_request_params.each do |k,v|
  post_body << "--#{BOUNDARY}\r\n"
  if v.is_a?(IO)
    post_body << "Content-Disposition: form-data; name="#{k}"; filename="#{filename}"\r\n"
    post_body << "\r\n"
    post_body << File.read(file)
    post_body << "\r\n"
  else
    post_body << "Content-Disposition: form-data; name="#{k}"\r\n\r\n"
    post_body << v.to_s + "\r\n"
  end
end

post_body << "--#{BOUNDARY}--\r\n"

uri = URI.parse(first_response["action"])
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request.body = post_body.join
request["Content-Type"] = "multipart/form-data, boundary=#{BOUNDARY}"
response = http.request(request)

exit(response.code == second_request_params["success_action_status"].to_s)
```
### Syncing a created Attachment
Syncing marks an upload as complete, and verifies its existence on the CDN.
A sync request can be made as follows:

```
curl -X PUT "https://api.mavenlink.com/api/v1/attachments/2/sync.json"
```
## Kantata OX Server Upload
For small attachments (< 10MB), you may upload to our servers and skip the 3-step direct CDN upload process.
Doing so requires one field, `attachment`, with two required attributes:
- `type` (required) must be either `post_attachment` or `receipt`.
- `data` (required) is the multipart/form-data encoded file contents.

After successfully creating an attachment its metadata will be returned in JSON format with an HTTP 200
status code. To upload a file using the `curl` utility, you would run a command like this one:

```
curl --form "attachment[data]=@test.rb" --form "attachment[type]=post_attachment" "https://api.mavenlink.com/api/v1/attachments.json"
```
This endpoint returns structured Attachment objects.
As with all Kantata OX API endpoints, the returned data will be referenced in sorted order in the `results` array
and will be indexed by ID in the `attachments` top-level JSON key.
Please see our [Response Format](#section/Response-Format) section for more information.

Endpoint: POST /attachments
Version: 1.0.0

## Request fields (application/json):

  - `attachment` (object)

  - `attachment.type` (string, required)
    Indicates the type of Attachment within Kantata OX.  Allowed values are: receipt or post_attachment.
A receipt is attached to an Expense, and a post_attachment is attached to a Post.

  - `attachment.direct` (boolean)
    Whether or not this is a direct CDN upload.  If direct is set to true, the filename field is required.
If direct is set to false or is not present, the data field is required.

  - `attachment.data` (string)
    The multipart/form-data encoded file contents.  Only used if direct is not set to true.  Note that the
maximum allowed size for file data uploads is 10MB.  For larger files, use a direct CDN upload.

  - `attachment.filename` (string)
    The filename of the file to be uploaded.  Only used if direct is set to true.

## Response 200 fields (application/json):

  - `count` (integer)

  - `meta` (object)

  - `meta.count` (integer)

  - `meta.page_count` (integer)

  - `meta.page_number` (integer)

  - `meta.page_size` (integer)

  - `results` (array)

  - `results.key` (string)

  - `results.id` (string)

## Response 400 fields (application/json):

  - `errors` (array)

  - `errors.type` (string)

  - `errors.message` (string)

## Response 401 fields (application/json):

  - `errors` (array)

  - `errors.type` (string)

  - `errors.message` (string)

## Response 403 fields (application/json):

  - `errors` (array)

  - `errors.type` (string)

  - `errors.message` (string)

## Response 404 fields (application/json):

  - `errors` (array)

  - `errors.type` (string)

  - `errors.message` (string)

## Response 422 fields (application/json):

  - `errors` (array)

  - `errors.type` (string)

  - `errors.message` (string)

## Response 503 fields (application/json):

  - `errors` (array)

  - `errors.type` (string)

  - `errors.message` (string)

